import { _decorator, Component, Node, CCInteger, resources, Prefab, instantiate, ImageAsset, SpriteFrame, Texture2D, Vec3, Sprite, tween, clamp, find } from 'cc';
import { Card, ImageRes } from './Card';
const { ccclass, property } = _decorator;

@ccclass('GameManager')
export class GameManager extends Component {
    @property({type:[Node], displayName: "定位节点"})
    placeNodes: Array<Node> = []

    @property({type:[Node], displayName: "放置节点"})
    harvestNodes: Array<Node> = []

    @property({type: CCInteger, displayName: "卡片数量", tooltip: "3 的倍数"})
    cardNum: number = 0

    @property({type:Node, displayName: "重新开始"})
    reStartNode: Node = null

    // 定义一个卡片数组存储卡片
    cardArray: Array<Card> = new Array<Card>()

    // 定义一个数组存储图片信息
    spriteArray: Array<ImageRes> = []

    // 用于记录资源加载完成数量
    loadedCount: number = 0

    // 记录每个定位节点放置的卡片，为字典信使，每个键值对应一个数组，一个节点可以放置多个卡片
    placedMap: Map<Node, Array<Card>> = new Map<Node, Array<Card>>()

    inited: boolean = false

    selectedCount: number = 0

    selectedArray: Array<Card> = []

    score: number = 0

    start() {
        // 这里我们需要加载 18 个卡片
        for (let i = 0; i < this.cardNum ; i++) {
            // 第一个参数时资源路径相对 resources 目录，第二个参数是资源类型，第三个参数是加载完成后执行的逻辑
            resources.load("prefabs/square", Prefab, (err, prefab)=>{
                // 将预制体实例化成 Node 对象
                var square = instantiate(prefab)
                // 声明一个 card，用于存储 卡片所有信息
                var card = new Card()
                // 初始化卡片信息
                card.cardView = square;
                // 将卡片引用保存到数组中
                this.cardArray.push(card)
                // 资源计数 +1
                this.loadedCount++
              })
            
            // 图片资源名称获取，因为我们只有 6 张图片，而 卡片数量有 18 张，所以需要除以 6 草能获取正确额名称
            var cardName = "items_" + (Math.floor(i / 6) + 1)
            // 加载图片资源
            resources.load("src/items/" + cardName, ImageAsset, (err, asset)=>{
                // 资源计数 +1
                this.loadedCount++
                // 定义一个精灵对象
                const frame = new SpriteFrame()
                // 定义一张贴图存储图片信息
                const tex = new Texture2D();
                // 将图片资源赋给贴图
                tex.image = asset;
                // 将贴图赋给精灵
                frame.texture = tex
                // 声明一个图片对象，并存储精灵信息
                var imageRes = new ImageRes()
                imageRes.spriteFrame = frame
                imageRes.name = asset.nativeUrl
                // 将资源放进数组中
                this.spriteArray.push(imageRes)
            })
        }

        // 初始化定位节点记录信息
        this.placeNodes.forEach(element => {
            this.placedMap.set(element, [])
        });
    }

    update(deltaTime: number) {
        if(!this.inited && this.loadedCount == this.cardNum * 2)
        {
            this.inited = true
            this.initCard()
        }
    }

    initCard(){
        // 卡片计数
        var count = 0
        // 便利卡片数组，对每个数组进行初始化
        this.cardArray.forEach(card => {
            // 获取卡片放置的位置索引，floor 向下取整，这里每个索引放两张卡片
            const placeIndex = Math.floor(count / 2)
            // 获取到定位节点
            var place = this.placeNodes[placeIndex]
            // 随机一个图片处来
            var imageRes = this.spriteArray[Math.floor(Math.random() * this.spriteArray.length)]
            // 获取定位节点的数组信息
            var tempArray = this.placedMap.get(place)
            // 将卡片节点放到定位节点下
            card.cardView.setParent(place)
            // 设置卡片相对于定位节点的位置
            card.cardView.setPosition(new Vec3().add3f(0, -15 * tempArray.length, 0))
            // 获取卡片的图片精灵对象
            var cardSprite = card.cardView.getChildByName("Sprite")
            // 获取卡片的精灵组件
            var spriteCom = cardSprite.getComponent(Sprite)
            // 赋值
            spriteCom.spriteFrame = imageRes.spriteFrame
            // 记录卡片的名字信息
            card.url = imageRes.name
            card.cardSprite = cardSprite
            for (let index = 0; index < tempArray.length; index++) {
                const element = tempArray[index];
                element.setGray(true)
            }
            card.initEvent(()=>{
                this.moveCard(card)
            })
            //  记录卡片到定位节点的数组下
            tempArray.push(card)
            // 移除卡片资源数组中的记录
            var i = this.spriteArray.indexOf(imageRes);
            if(i > -1){
                this.spriteArray.splice(i, 1);
            }
            // 计数加一
            count++
        });
    }

    moveCard(card: Card){
        // 获取需要移动到的定位节点，也就是终点
        const aimNode = this.harvestNodes[this.selectedCount]
        // 获取终点的世界坐标
        const aimPos = aimNode.getWorldPosition()
        // 获取当前节点坐标
        const curPos = card.cardView.getWorldPosition()
        // 开始计算需要移动的距离 = 目标位置 - 当前位置
        const moveVec = new Vec3()
        Vec3.subtract(moveVec, aimPos, curPos)
        // 保存选中引用
        this.selectedArray.push(card)
        // 移动数量加一
        this.selectedCount++
        // 执行移动动画
        tween(card.cardView).by(0.5, {
            // 从当前位置移动
            position: moveVec
        }).call((event)=>{
            // 动画执行完成后调用函数
            this.moveOver(event, card)
        }).start()
        
        // 记录+1
        this.score++

        // 因为表面上的卡片移走，所以下面的卡片需要可以显示及点击
        this.placedMap.forEach((cards, place) => {
            // 找当当前卡片节点所在的位置
            const index = cards.indexOf(card)
            if(index == -1) return
            // 移除当前卡片
            cards.length--
            if(cards.length == 0) return
            // 弃用下一层的卡片
            const newCard = cards[cards.length - 1]
            newCard.setGray(false)
        })
    }

    moveOver(vent, card: Card){
        // 移动过后卡片将禁用
        card.setButton(false)
        var count = 0
       
        // 检测有几张同名卡片
        this.selectedArray.forEach(element => {
           if(element.url == card.url) count++
        });

        // 如果卡片是 3 的倍数，则执行消除逻辑
        if(count % 3 == 0){
            // 消除逻辑
            this.removeCard(card.url)
            // 移动中的数量 -3
            this.selectedCount -= 3
            // 这里做一层保险，保证移动中的数量只能在 0-6
            this.selectedCount = clamp(this.selectedCount, 0, 6)
        }
        
        // 如果移动中数量 > 6 则游戏失败
        if(this.selectedCount >= 6){
            this.reStartNode.active = true
            return
        }

        // 如果移动总数 = 卡片总数，则胜利
        if(this.score >= this.cardNum){
            // 重开逻辑
            this.reStartNode.active = true
        }
    }

    removeCard(url: string){
       // 需要移除的卡片数组
       var removeEle = []
       // 遍历同名卡片并记录
       this.selectedArray.forEach(element => {
           if(element.url == url){
               // 隐藏卡片
               element.cardView.active = false
               // 放入待删除数组中
               removeEle.push(element)
           }
       })

       // 删除移动中的卡片引用
       removeEle.forEach(element => {
           var i = this.selectedArray.indexOf(element);
           if(i > -1)
               this.selectedArray.splice(i, 1);
           }
       );

       // 重新整理放置槽
       var startIndex = 0
       this.selectedArray.forEach(element => {
           // 获取放置节点
           const aimNode = this.harvestNodes[startIndex++]
           const aimPos = aimNode.getWorldPosition()
           const curPos = element.cardView.getWorldPosition()
           const moveVec = new Vec3()
           Vec3.subtract(moveVec, aimPos, curPos)
           // 移动卡片
           tween(element.cardView).by(0.2, {
               position: moveVec
           }).start()
       }); 
    }
}

